package com.piece.admin.controller.system;

import com.piece.admin.model.TbSysMenu;
import com.piece.admin.model.TbSysRole;
import com.piece.admin.service.TbSysMenuService;
import com.piece.admin.service.TbSysRoleService;
import com.piece.admin.support.TranslateEntity;
import com.piece.core.framework.annotation.permission.AclPermission;
import com.piece.core.framework.annotation.permission.SubmitPermission;
import com.piece.core.framework.constant.ExceptionConstants;
import com.piece.core.framework.enums.sql.SqlKey;
import com.piece.core.framework.support.bootstrap.DataTable;
import com.piece.core.framework.support.bootstrap.Order;
import com.piece.core.framework.support.bootstrap.QueryTable;
import com.piece.core.framework.support.bootstrap.TreeData;
import com.piece.core.framework.support.convert.Convert;
import com.piece.core.framework.support.response.AjaxResponse;
import com.piece.core.framework.util.object.ClassUtil;
import com.piece.core.framework.util.object.ObjectUtil;
import com.piece.core.framework.util.basic.I18nUtil;
import com.piece.core.framework.util.string.StringUtil;
import com.piece.core.log.client.dto.UserDTO;
import com.piece.core.log.config.UserContextHolder;
import com.piece.core.web.controller.FrameWorkController;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@RestController
@Api(tags = {"菜单管理"})
@RequestMapping("/api/system/menu")
public class SysMenuController extends FrameWorkController {

    @Autowired
    protected TranslateEntity translateEntity;

    @Resource
    private TbSysMenuService tbSysMenuService;

    @Resource
    private TbSysRoleService tbSysRoleService;

    @PostMapping("/list")
    @AclPermission(code = "system:menu:view")
    @ApiOperation(value = "查询菜单列表")
    @ApiImplicitParam(value = "查询条件", dataTypeClass = QueryTable.class, type = "body")
    public List list() {
        QueryTable queryTable = initTable();
        List<Order> orders = new ArrayList<>();
        orders.add(new Order("orderNum", SqlKey.ASC));
        queryTable.setOrder(orders);
        DataTable dataTable = tbSysMenuService.findPage(queryTable);
        return dataTable.getData();
    }

    @PostMapping("/table")
    @AclPermission(code = "system:menu:view")
    @ApiOperation(value = "查询菜单分页数据")
    @ApiImplicitParam(value = "查询条件", dataTypeClass = QueryTable.class, type = "body")
    public AjaxResponse table() {
        QueryTable queryTable = initTable();
        DataTable dataTable = tbSysMenuService.findPage(queryTable);
        return success(dataTable);
    }

    @PostMapping("/treeTable")
    @AclPermission(code = "system:menu:view")
    @ApiOperation(value = "查询菜单分页树数据")
    @ApiImplicitParam(value = "查询条件", dataTypeClass = QueryTable.class, type = "body")
    public AjaxResponse treeTable() {
        QueryTable queryTable = initTable();
        Map<String, Object> params = queryTable.getParams();
        queryTable.setParams(params);
        if (ObjectUtil.isEmpty(params.get("Q_menuName_S_LK"))) {
            params.put("Q_parentId_L_EQ", 0);
        }
        queryTable.setOrder(Stream.of(new Order("orderNum", SqlKey.ASC)).collect(Collectors.toList()));
        DataTable dataTable = tbSysMenuService.findPage(queryTable);
        List<TbSysMenu> data = new ArrayList<>();
        List<TbSysMenu> parentMenus = dataTable.getData();
        List<TbSysMenu> allMenus = tbSysMenuService.findAll();
        for (Iterator<TbSysMenu> iterator = parentMenus.iterator(); iterator.hasNext();) {
            TbSysMenu menu = iterator.next();
            menu.setChildren(tbSysMenuService.findChildMenus(allMenus, menu.getMenuId()));
            data.add(menu);
        }
        dataTable.setData(data);
        return success(dataTable);
    }

    @GetMapping("/load")
    @AclPermission(code = "system:menu:view")
    @ApiOperation(value = "加载菜单表单")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "菜单ID"),
            @ApiImplicitParam(name = "pid", value = "菜单父ID")
    })
    public AjaxResponse loadForm() {
        long id = Convert.toLong(getRequest().getParameter("id"), 0L);
        long pid = Convert.toLong(getRequest().getParameter("pid"), 0L);
        String parentName = "主目录";
        TbSysMenu menu = new TbSysMenu(), p_menu = null;
        if (id != 0) {
            menu = tbSysMenuService.findById(id);
            pid = menu.getParentId();
        }
        if (pid != 0) {
            p_menu = tbSysMenuService.findById(pid);
            parentName = p_menu.getMenuName();
        }
        menu.setParentId(pid);
        menu.setParentName(parentName);
        return success(menu);
    }

    @SubmitPermission
    @PostMapping("/save")
    @AclPermission(code = "system:menu:add,system:menu:edit")
    @ApiOperation(value = "保存菜单表单")
    @ApiImplicitParam(value = "菜单表单", dataTypeClass = TbSysMenu.class, type = "body")
    public AjaxResponse save() {
        TbSysMenu menu;
        try {
            Long id = Convert.toLong(getRequest().getParameter("menuId"));
            if (ClassUtil.isEmpty(id)) {
                menu = new TbSysMenu();
                setDefaultInfo(menu, true);
            } else {
                menu = tbSysMenuService.findById(id);
                setDefaultInfo(menu, false);
            }
            initDB(menu);
            tbSysMenuService.insertOrUpdate(menu);
            return success(I18nUtil.message(ExceptionConstants.SAVE_SUCCESS), null);
        } catch (Exception e) {
            return error(I18nUtil.message(ExceptionConstants.SAVE_FAILURE), e.getMessage());
        }
    }

    @SubmitPermission
    @PostMapping("/delete")
    @AclPermission(code = "system:menu:delete")
    @ApiOperation(value = "删除菜单")
    @ApiImplicitParam(name = "ids", value = "菜单ID集合")
    public AjaxResponse delete() throws Exception {
        String ids = getRequest().getParameter("ids");
        if (StringUtil.isNotEmpty(ids)) {
            tbSysMenuService.delete(Convert.toLongArray(ids));
        }
        return success(I18nUtil.message(ExceptionConstants.DELETE_SUCCESS), null);
    }

    /**
     * 加载所有菜单列表树
     */
    @PostMapping("/treeData")
    @AclPermission(code = "system:menu:view")
    @ApiOperation(value = "加载所有菜单列表树")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "roleId", value = "角色ID"),
            @ApiImplicitParam(name = "selected", value = "已选菜单ID"),
            @ApiImplicitParam(name = "from", value = "查询来源", allowableValues = "vue")
    })
    public List<TreeData> treeData() {
        String selected = getRequest().getParameter("selected");
        String roleId = getRequest().getParameter("roleId");
        // 请求来源
        String from = getRequest().getParameter("from");
        List<TreeData> result;
        if (StringUtil.isNotEmpty(roleId)) {
            TbSysRole role = tbSysRoleService.findById(Convert.toLong(roleId));
            result = tbSysMenuService.findTreeData(role);
        } else if (StringUtil.isNotEmpty(selected)) {
            List<TbSysMenu> list = tbSysMenuService.findAll();
            result = tbSysMenuService.findTreeData(list, true, Convert.toStrList(selected), true);
        } else {
            result = tbSysMenuService.findTreeData();
        }

        if ("vue".equals(from)) {
            TreeData root = TreeData.builder()
                    .id("0")
                    .name("菜单列表")
                    .build();
            result = findChildTreeData(result, Convert.toStr(root.getPId(), "0"));
            root.setChildren(result);
            List<TreeData> convertResult = new ArrayList<>();
            convertResult.add(root);
            return convertResult;
        }
        return result;
    }

    private void setDefaultInfo(TbSysMenu menu, boolean insert) {
        UserDTO user = UserContextHolder.get();
        if (insert) {
            menu.setCreateBy(user.getId());
            menu.setCreateTime(new Date());
        }
        menu.setUpdateBy(user.getId());
        menu.setUpdateTime(new Date());
    }
}
